#!/bin/bash

# Default values
NUM_RUNS=30
CLEAR_CACHE=false # Set to true to attempt cache clearing (requires sudo)

# --- Helper Functions ---
usage() {
    echo "Usage: $0 \"<command>\" <source_path> <dest_path> [--runs <num_runs>] [--clear-cache]"
    echo "  <command>: The copy command to execute (e.g., \"./copy_rw\", \"cp -r\"). Must be quoted."
    echo "  <source_path>: Path to the source file or directory."
    echo "  <dest_path>: Path for the destination (will be removed and recreated)."
    echo "  --runs <num_runs>: (Optional) Number of times to run the command for averaging (default: 3)."
    echo "  --clear-cache: (Optional) Attempt to clear system page cache before each run (requires sudo)."
    exit 1
}

print_error() {
    echo "Error: $1" >&2
    usage
}

# --- Positional Argument Parsing ---
if [[ $# -lt 3 ]]; then
    print_error "Missing required arguments: command, source_path, dest_path."
fi

COMMAND_TO_RUN="$1"
SOURCE_PATH="$2"
DEST_PATH="$3"
shift 3 # Remove the first three arguments, leaving optional ones

# --- Optional Argument Parsing ---
while [[ $# -gt 0 ]]; do
    key="$1"
    case $key in
        --runs)
        if [[ -z "$2" ]] || ! [[ "$2" =~ ^[0-9]+$ ]] || [[ "$2" -le 0 ]]; then
             print_error "Invalid value for --runs. Must be a positive integer."
        fi
        NUM_RUNS="$2"
        shift; shift
        ;;
        --clear-cache)
        CLEAR_CACHE=true
        shift
        ;;
        *) # unknown option
        print_error "Unknown optional argument $1"
        ;;
    esac
done


# --- Input Validation ---
# Basic validation for command presence is done by checking $# initially
if ! [[ -e "$SOURCE_PATH" ]]; then
    echo "Error: Source path '$SOURCE_PATH' does not exist." >&2
    exit 1
fi
# Destination path validation is less critical as it will be created/removed

# --- Execution and Timing ---
total_real_time=0
echo "Running command '$COMMAND_TO_RUN' from '$SOURCE_PATH' to '$DEST_PATH' for $NUM_RUNS runs..."

for (( i=1; i<=NUM_RUNS; i++ )); do
    echo "--- Run $i/$NUM_RUNS ---"

    # Clean destination before run
    rm -rf "$DEST_PATH"
    # Recreate dest if source is a directory, otherwise let the command create the file
    # Note: This simple check might fail if source path itself doesn't exist,
    # but we checked SOURCE_PATH existence earlier.
    if [[ -d "$SOURCE_PATH" ]]; then
        mkdir -p "$DEST_PATH" || { echo "Error: Failed to create destination directory '$DEST_PATH'." >&2; exit 1; }
    fi


    # Optional: Clear cache (use with caution and requires sudo)
    if [[ "$CLEAR_CACHE" = true ]]; then
        echo "Attempting to clear cache (requires sudo)..."
        sync
        sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches' || echo "Warning: Failed to clear cache. Proceeding anyway."
        sleep 1 # Give system a moment
    fi

    # Execute the command and capture time output (using time -p for POSIX format)
    # The command needs to handle source and dest arguments itself
    # We redirect stderr (where `time -p` outputs) to a temporary file
    TIME_OUTPUT_FILE=$(mktemp)
    # Use eval to correctly handle commands with spaces/arguments within the quoted string
    # Pass source and dest as arguments to the command being timed
    eval time -p $COMMAND_TO_RUN "$SOURCE_PATH" "$DEST_PATH" 2> "$TIME_OUTPUT_FILE"
    COMMAND_EXIT_CODE=$?

    if [[ $COMMAND_EXIT_CODE -ne 0 ]]; then
         echo "Error: Command exited with status $COMMAND_EXIT_CODE during run $i." >&2
         cat "$TIME_OUTPUT_FILE" >&2 # Show time output which might contain errors
         rm "$TIME_OUTPUT_FILE"
         # Decide if you want to exit immediately or continue other runs
         # exit 1
         echo "Warning: Run $i failed. Excluding from average."
         # To exclude from average, we can simply not add to total_real_time
         # and potentially decrement a counter for valid runs if needed.
         # For simplicity here, we'll just warn and continue.
         # If calculating average, ensure divisor reflects successful runs only.
         # Let's adjust to exit on first failure for clearer results in the lab.
         exit 1
    fi

    # Extract real time from the time output file
    real_time=$(grep '^real' "$TIME_OUTPUT_FILE" | awk '{print $2}')

    if [[ -z "$real_time" ]]; then
        echo "Error: Could not extract real time from time output during run $i." >&2
        cat "$TIME_OUTPUT_FILE" >&2
        rm "$TIME_OUTPUT_FILE"
        exit 1
    fi

    echo "Run $i real time: $real_time s"
    total_real_time=$(awk "BEGIN {print $total_real_time + $real_time}")

    rm "$TIME_OUTPUT_FILE" # Clean up temp file
done

# --- Calculate and Print Average ---
# Ensure division by zero doesn't happen if all runs failed (though we exit on first failure now)
if [[ $NUM_RUNS -gt 0 ]]; then
    average_real_time=$(awk "BEGIN {printf \"%.3f\", $total_real_time / $NUM_RUNS}")
else
    average_real_time="N/A (No successful runs)"
fi


echo "---------------------"
echo "Command: $COMMAND_TO_RUN"
echo "Source: $SOURCE_PATH"
echo "Destination: $DEST_PATH"
echo "Total real time over $NUM_RUNS runs: $total_real_time s"
echo "Average real time: $average_real_time s"
echo "---------------------"

exit 0
